package cn.xinfei.xdecision.engine.runner.utils;

import cn.xinfei.xdecision.common.model.component.strategyout.OutCondition;
import cn.xinfei.xdecision.common.model.enginex.po.EngineNode;
import cn.xinfei.xdecision.common.model.enginex.runner.ExpressionParam;
import cn.xinfei.xdecision.common.utils.enums.enginex.NodeTypeEnum;
import cn.xinfei.xdecision.common.utils.exception.ApiException;
import cn.xinfei.xdecision.common.utils.exception.enums.ErrorCodeEnum;
import cn.xinfei.xdecision.common.utils.util.runner.StrUtils;
import cn.xinfei.xdecision.common.utils.util.runner.jeval.EvaluationException;
import cn.xinfei.xdecision.common.utils.util.runner.jeval.Evaluator;
import cn.xinfei.xdecision.common.utils.util.strategyx.DataCleanUtils;
import cn.xinfei.xdecision.engine.runner.expressions.ExpressExecutor;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

//底层执行的工具类
@Slf4j
public class ExecuteUtils {
    private static final Logger logger = LoggerFactory.getLogger(ExecuteUtils.class);

    public static boolean judgeOutCondition(String condition) throws EvaluationException {
        //条件为空则符合输出
        if (null == condition || "".equals(condition)) {
            return true;
        }
        OutCondition outCondition;
        try {
            outCondition = JSON.parseObject(condition, OutCondition.class);
        } catch (Exception e) {
            //字符串转json失败
            log.error("judgeOutCondition condition parse error={}", e.getMessage(), e);
            return true;
        }
        String logical = outCondition.getLogical();
        List<ExpressionParam> conditionList = outCondition.getConditionList();
        if (null == logical || null == conditionList || conditionList.size() < 1) {
            return true;
        }
        boolean result = false;
        switch (logical) {
            case "||":
                result = false;
                for (ExpressionParam expression : conditionList) {
                    if (ExpressExecutor.getExpressionResult(expression)) {
                        return true;
                    }
                }
                break;
            case "&&":
                result = true;
                for (ExpressionParam expression : conditionList) {
                    if (!ExpressExecutor.getExpressionResult(expression)) {
                        return false;
                    }
                }
                break;
        }
        return result;
    }


    //根据key，分不同类型取出值
//    public final static Object getValueByKey(Integer variableType, Map<String, Object> params, String paramKey, List<JSONObject> list) {
//        Object result = paramKey;
//        if (variableType != null) {
//            switch (variableType) {
//                case ParamTypeConst
//                        .CONSTANT:
//                    //常量类型
//                    result = paramKey;
//                    break;
//                case ParamTypeConst
//                        .VARIABLE:
//                    //变量类型
//                    result = getObjFromMap(params, paramKey);
//                    break;
//                case ParamTypeConst
//                        .CUSTOM:
//                    //自定义脚本类型
//                    //todo shiyusen
//                    if (list == null || list.isEmpty()) {
////                        result = getObjFromScript(params, paramKey);
//                    } else {
////                        result = getObjFromScript(params, paramKey, list);
//                    }
//                    break;
//                case ParamTypeConst
//                        .REGEX:
//                    //正则表达式类型
//                    result = ScriptExecutor.getObjFromRegex(params, paramKey);
//            }
//        }
//        return result;
//    }

    //从map中取值
//    public final static Object getObjFromMap(Map<String, Object> input, String key) {
//        if (StringUtils.isBlank(key)) {
//            return "";
//        }
//        if (input == null) {
//            input = new ConcurrentHashMap<>();
//        }
//        String[] array = key.split("\\.");
//        //如果当前变量池中未找到此变量则需要获取
//        if (input.get(array[0]) == null && !array[0].startsWith("%")) {
//            List<String> strings = new ArrayList<String>();
//            strings.add(array[0]);
//            boolean result = getFieldToInputByEns(strings, input);
//            if (!result) {
//                return "";
//            }
//        }
//        return getObjFromMap(input, array);
//    }

    //从map中找到需要的对象并返回
    public final static Object getObjFromMap(Map<String, Object> input, String[] array) {
        if (array.length == 1) {
            Object o = input.get(array[0]);
            if (o == null) {
                return "";
            }
            return o;
        }
        Map map = input;
        for (int i = 0; i < array.length; i++) {
            String childKey = array[i];
            //判断是否能找到key
            if (map.containsKey(childKey)) {
                Object o = map.get(childKey);
                if (i == array.length - 1) {
                    return map.get(childKey);
                }
                //如果是数组取length
                if (i == array.length - 2) {
                    if ("length()".equals(array[array.length - 1])) {
                        return JSON.toJavaObject(JSON.parseArray(JSON.toJSONString(o)), ArrayList.class).size();
                    } else if ("array()".equals(array[array.length - 1])) {
                        return JSON.parseArray(JSON.toJSONString(o));
                    }
                }
                //未找到最后一个数组元素则将其识别为map
                map = JSON.toJavaObject(JSON.parseObject(JSON.toJSONString(o)), Map.class);
            }
        }
        return "";
    }

    //调用commonService根据ens取参数
//    public static boolean getFieldToInputByEns(List<String> fieldEns, Map<String, Object> input) {
//        boolean result = commonService.getEngineField(fieldService.selectFieldListByEns(fieldEns), input);
//        return result;
//    }
    //调用commonService根据ids取参数
//    private static boolean getFieldToInputByIds(List<Long> ids, Map<String, Object> input) {
//        boolean result = commonService.getFieldByIds(ids, input);
//        return result;
//    }

    // 解析nodeJson
    public final static List<Map> getExecuteListFromNodeJson(EngineNode engineNode) {
        JSONObject nodeJson = JSON.parseObject(engineNode.getNodeJson());
        String strategyStr = null;
        NodeTypeEnum nodeTypeEnum = NodeTypeEnum.adapad(engineNode.getNodeType());
        switch (nodeTypeEnum) {
            case RULE_BASE://规则集
                strategyStr = JSON.toJSONString(nodeJson.getJSONObject("executeGroup").get("strategyList"));
                break;
            case SCORECARD://评分卡
                strategyStr = JSON.toJSONString(nodeJson.getJSONArray("scorecardList"));
                break;
//            case 5://名单库
//                strategyStr = JSON.toJSONString(nodeJson.getJSONArray("listDbList"));
//                break;
//            case 15://模型
//                strategyStr = JSON.toJSONString(nodeJson.getJSONArray("modelList"));
//                break;
            case DECISION_TABLES://决策表
                strategyStr = JSON.toJSONString(nodeJson.getJSONArray("decisionTableList"));
                break;
            case DECISION_TREE://决策树
                strategyStr = JSON.toJSONString(nodeJson.getJSONArray("decisionTreeList"));
                break;

        }
        List<Map> maps = JSON.parseArray(strategyStr, Map.class);
        return maps;
    }

    //获取执行用的id列表
    public final static List<Long> getExecuteIdList(EngineNode engineNode, String idKey) {
        List<Map> maps = ExecuteUtils.getExecuteListFromNodeJson(engineNode);
        List<Long> executeIdList = new ArrayList<>();
        if (maps != null && maps.size() > 0) {
            for (Map map : maps) {
                if (map.containsKey(idKey)) {
                    Object o = map.get(idKey);
                    if (o != null) {
                        Long id = StrUtils.strToLong(String.valueOf(o));
                        if (id != null) {
                            executeIdList.add(id);
                        }
                    }

                }
            }
        }
        return executeIdList;
    }


    //根据key，分不同类型取出值
//    public final static Object getValueByKeyYiHao(Integer variableType, Map<String, Object> params, String paramKey, JSONObject collectionObject) {
//        Object result = paramKey;
//        if (variableType != null) {
//            switch (variableType) {
//                case ParamTypeConst
//                        .CONSTANT:
//                    //常量类型
//                    result = paramKey;
//                    break;
//                case ParamTypeConst
//                        .VARIABLE:
//                    //变量类型
//                    result = getObjFromMap(params, paramKey);
//                    break;
//                case ParamTypeConst
//                        .CUSTOM:
//                    //自定义脚本类型
//                    result = getObjFromScriptYiHao(paramKey, collectionObject);
//                    break;
//                case ParamTypeConst
//                        .REGEX:
//                    //正则表达式类型
//                    //todo shiyusen
////                    result = getObjFromRegex(params, paramKey);
//            }
//        }
//        return result;
//    }

    //处理集合中的特殊自定义
    private final static Object getObjFromScriptYiHao(String outputValue, JSONObject collectionObject) {
        JSONObject formulaJson = JSON.parseObject(outputValue);
        Object farr = formulaJson.get("farr");
        Map<String, Object> fieldMap = new HashMap<>();
        if (farr != null && !"".equals(farr)) {
            List<JSONObject> fieldList = JSONArray.parseArray(JSON.toJSONString(farr), JSONObject.class);
            for (JSONObject jsonObject : fieldList) {
                String fieldCn = jsonObject.getString("fieldCn");
                String fieldEn = jsonObject.getString("fieldEn");
                Object opValue = DataCleanUtils.getObjByKeyAndJson(collectionObject, fieldEn);
                fieldMap.put(fieldCn, opValue);
            }
        }
        //取出groovy脚本
        Object result = executeScriptYiHao(formulaJson, fieldMap);
        return result;
    }

    //执行自定义脚本
    private final static Object executeScriptYiHao(JSONObject formulaJson, Map<String, Object> fieldMap) {
        String formula = formulaJson.getString("formula");
        //替换掉特殊的字符
        formula = formula.replace("&gt;", ">"); //3&gt;=6 && 3&lt; 12
        formula = formula.replace("&lt;", "<");
        //正则匹配自定义中用到的变量对其进行替换
        Pattern pattern = Pattern.compile("@[a-zA-Z0-9_\u4e00-\u9fa5()（）-]+@");
        Matcher matcher = pattern.matcher(formula);
        String subexp = formula;
        String exp = "";
        int j = 0;
        while (matcher.find()) {
            String fieldCn = matcher.group(0).replace("@", "");
            Object fieldCnValue = fieldMap.get(fieldCn);
            if (fieldCnValue == null) {
                return "";
            }
            exp += subexp.substring(j, matcher.end()).replace("@" + fieldCn + "@", fieldCnValue.toString());
            j = matcher.end();
        }

        exp += formula.substring(j, formula.length());
        Evaluator evaluator = new Evaluator();
        Object result = "";
        try {
            //执行公式
            result = evaluator.evaluate(exp);

            if (result.toString().startsWith("'")) {
                //字符串
                result = result.toString().replace("'", "");
            } else {
                //数值
                if (StrUtils.isNum(result.toString())) {
                    String[] split = result.toString().split("\\.");
                    if (split.length > 1 && StrUtils.strToLong(split[1]) > 0) {
                        result = StrUtils.strToDouble(result.toString());
                    } else {
                        result = StrUtils.strToLong(split[0]);
                    }
                }
            }
        } catch (EvaluationException e) {
            logger.error("自定义执行异常", e);
            throw new ApiException(ErrorCodeEnum.RUNNER_CUSTOM_ERROR.getCode(), ErrorCodeEnum.RUNNER_CUSTOM_ERROR.getMessage());
        }
        return result;
    }
}
